import 'dart:async';

typedef NetworkRequest = Future<bool> Function();

class RetryPolicy {
  final Duration successDelay;
  final Duration failureDelay;
  final int? maxRetries; // 可选：最大重试次数
  final bool Function(dynamic error)? retryPredicate; // 可选：自定义重试条件

  const RetryPolicy({
    required this.successDelay,
    required this.failureDelay,
    this.maxRetries,
    this.retryPredicate,
  });
}

class NetworkService {
  Timer? _timer;
  bool _isRunning = false;
  int _retryCount = 0;
  final RetryPolicy _policy;
  final NetworkRequest _request;
  final void Function()? _onSuccess;
  final void Function(dynamic error)? _onFailure;

  NetworkService({
    required NetworkRequest request,
    required RetryPolicy policy,
    void Function()? onSuccess,
    void Function(dynamic error)? onFailure,
  })  : _request = request,
        _policy = policy,
        _onSuccess = onSuccess,
        _onFailure = onFailure;

  // 启动循环请求
  void start() {
    if (_isRunning) return;
    _isRunning = true;
    _retryCount = 0;
    _executeRequest();
  }

  // 停止循环请求
  void stop() {
    _timer?.cancel();
    _isRunning = false;
    _retryCount = 0;
  }

  // 执行请求并处理结果
  Future<void> _executeRequest() async {
    try {
      final success = await _request();
      _retryCount = 0; // 重置重试计数

      if (success) {
        _onSuccess?.call();
        _scheduleNextRequest(_policy.successDelay);
      } else {
        _handleFailure(Exception('Request failed'));
      }
    } catch (e) {
      _handleFailure(e);
    }
  }

  void _handleFailure(dynamic error) {
    _retryCount++;

    // 检查是否超过最大重试次数
    if (_policy.maxRetries != null && _retryCount > _policy.maxRetries!) {
      print('达到最大重试次数: $_retryCount');
      stop();
      return;
    }

    // 检查自定义重试条件
    if (_policy.retryPredicate != null && !_policy.retryPredicate!(error)) {
      print('自定义条件阻止重试: $error');
      stop();
      return;
    }

    _onFailure?.call(error);
    _scheduleNextRequest(_policy.failureDelay);
  }

  void _scheduleNextRequest(Duration delay) {
    _timer = Timer(delay, () {
      if (_isRunning) _executeRequest();
    });
  }
}